import logging
logging.basicConfig(level=logging.INFO)

import asyncio
import os
import json
import time
from datetime import datetime
from model import User
from orm import create_pool
from aiohttp import web
from jinja2 import Environment, FileSystemLoader
from webhandle import add_routes, add_static
from config import configs
from handlers import COOKIE_NAME, cookie2user


def init_jinja2(app, **kw):
    logging.info('init jinja2...')
    options = dict(
        autoescape=kw.get('autoescape', True),
        block_start_string=kw.get('block_start_string', '{%'),
        block_end_string=kw.get('block_end_string', '%}'),
        variable_start_string=kw.get('variable_start_string', '{{'),
        variable_end_string=kw.get('variable_end_string', '}}'),
        auto_reload=kw.get('auto_reload', True)

    )
    path = kw.get('path', None)
    if path is None:
        path = os.path.join(os.path.dirname(
            os.path.abspath(__file__)), 'templates')
    logging.info('set jinja2 tempate path:%s' % path)
    env = Environment(loader=FileSystemLoader(path), **options)
    filters = kw.get('filters', None)
    if filters is not None:
        for name, f in filters.items():
            env.filters[name] = f

    app['__template__'] = env


# 编写用于输出日志的middleware
@web.middleware
async def logger(request, handler):
    logging.info('Request: %s %s' % (request.method, request.path))
    return await handler(request)


# 解析用户cookie绑定到request的__user__对象
@web.middleware
async def auth(request, handler):
    logging.info('check user: %s %s' % (request.method, request.path))
    request.__user__ = None
    cookie_str = request.cookies.get(COOKIE_NAME)
    if cookie_str:
        user = await cookie2user(cookie_str)
        if user:
            logging.info('set current user: %s' % user.email)
            request.__user__ = user
    if request.path.startswith('/manage/') and (request.__user__ is None or not request.__user__.admin):
        return web.HTTPFound('/signin')
    return (await handler(request))


@web.middleware
async def response(request, handler):
    logging.info('Response handler...')
    r = await handler(request)
    logging.info('response result = %s' % str(r))
    if isinstance(r, web.StreamResponse):  # StreamResponse是所有Response对象的父类
        return r  # 无需构造，直接返回
    if isinstance(r, bytes):
        logging.info('*' * 10)
        resp = web.Response(body=r)  # 继承自StreamResponse，接受body参数，构造HTTP响应内容
        # Response的content_type属性
        resp.content_type = 'application/octet-stream'
        return resp
    if isinstance(r, str):
        if r.startswith('redirect:'):  # 若返回重定向字符串
            return web.HTTPFound(r[9:])  # 重定向至目标URL
        resp = web.Response(body=r.encode('utf-8'))
        resp.content_type = 'text/html;charset=utf-8'  # utf-8编码的text格式
        return resp
    # r为dict对象时
    if isinstance(r, dict):
        # 在后续构造视图函数返回值时，会加入__template__值，用以选择渲染的模板
        template = r.get('__template__', None)
        if template is None:  # 不带模板信息，返回json对象
            resp = web.Response(body=json.dumps(
                r, ensure_ascii=False, default=lambda obj: obj.__dict__).encode('utf-8'))
            # ensure_ascii：默认True，仅能输出ascii格式数据。故设置为False。
            # default：r对象会先被传入default中的函数进行处理，然后才被序列化为json对象
            # __dict__：以dict形式返回对象属性和值的映射
            resp.content_type = 'application/json;charset=utf-8'
            return resp
        else:  # 带模板信息，渲染模板
            # app['__template__']获取已初始化的Environment对象，调用get_template()方法返回Template对象
            # 调用Template对象的render()方法，传入r渲染模板，返回unicode格式字符串，将其用utf-8编码
            r['__user__'] = request.__user__
            resp = web.Response(
                body=request.app['__template__'].get_template(template).render(**r))
            resp.content_type = 'text/html;charset=utf-8'  # utf-8编码的html格式
            return resp
    # 返回响应码
    if isinstance(r, int) and (600 > r >= 100):
        resp = web.Response(status=r)
        return resp
    # 返回了一组响应代码和原因，如：(200, 'OK'), (404, 'Not Found')
    if isinstance(r, tuple) and len(r) == 2:
        status_code, message = r
        if isinstance(status_code, int) and (600 > status_code >= 100):
            resp = web.Response(status=r, text=str(message))
    resp = web.Response(body=str(r).encode('utf-8'))  # 均以上条件不满足，默认返回
    resp.content_type = 'text/plain;charset=utf-8'  # utf-8纯文本
    return resp


def datetime_filter(t):
    delta = int(time.time() - t)
    minSec = 60  # 一分钟的秒数
    hourSec = 3600
    daySec = 86400
    yearSec = 604800
    if delta < minSec:
        return u'1分钟前'
    if delta < hourSec:
        return u'%s分钟前' % (delta // minSec)
    if delta < daySec:  # 一天的秒数
        return u'%s小时前' % (delta // hourSec)
    if delta < yearSec:
        return u'%s天前' % (delta // daySec)
    dt = datetime.fromtimestamp(t)
    return u'%s年%s月%s日' % (dt.year, dt.month, dt.day)


def index(request):
    return web.Response(body=b'<h1>Awesome</h1>', headers={'Content-Type': 'text/html'})


async def init(loop):
    app = web.Application(loop=loop, middlewares=[logger, auth, response])
    init_jinja2(app, filters=dict(datetime=datetime_filter))  # 用于过滤模板中的时间日期格式
    add_routes(app, 'handlers')
    add_static(app)
    await create_pool(loop=loop, **configs.db)
    srv = await loop.create_server(app.make_handler(), '0.0.0.0', 9000)
    logging.info('server started at http://127.0.0.1:9000...')
    return srv


# 添加用户测试代码
async def test(loop):
    await create_pool(loop, user='root', password='root', db='awesome')

    u = User(name='Test', email='test@example.com',
             passwd='1234567890', image='about:blank')

    await u.save()

loop = asyncio.get_event_loop()
# loop.run_until_complete(test(loop))
loop.run_until_complete(init(loop))
loop.run_forever()
loop.close()
